import React, { CSSProperties, useRef, useMemo, useEffect } from 'react';
import clsx from 'clsx';
import { ImageProps } from './PropsType';
import { isDef, addUnit } from '../utils';
import { useSetState } from '../hooks';
import useNamespace from '../utils/useNamespace';

const Image: React.FC<ImageProps> = ({
  fit,
  errorIcon,
  loadingIcon,
  showError = true,
  showLoading = true,
  block,
  className,
  children,
  style,
  width,
  height,
  radius,
  iconSize,
  alt = 'img',
  src,
  round,
  onClick,
  onLoad,
  onError,
  ...rest
}) => {
  const [bem] = useNamespace('image');
  const [status, setStatus] = useSetState({ loading: true, error: false });
  const imgRef = useRef<HTMLImageElement>(null);

  const computedStyle = useMemo(() => {
    const internalStyle: CSSProperties = { ...style };

    if (isDef(width)) {
      internalStyle.width = addUnit(width);
    }

    if (isDef(height)) {
      internalStyle.height = addUnit(height);
    }

    if (isDef(radius)) {
      internalStyle.overflow = 'hidden';
      internalStyle.borderRadius = addUnit(radius);
    }

    return internalStyle;
  }, [style, width, height, radius]);

  useEffect(() => {
    const payload = { error: false, loading: true } as typeof status;
    if (imgRef.current) {
      if (imgRef.current.complete) {
        payload.loading = false;
      } else {
        payload.loading = true;
      }
    }
    setStatus(payload);
  }, [src]);

  const handleLoad = (event: React.SyntheticEvent<HTMLImageElement>) => {
    setStatus({ loading: false });
    onLoad?.(event as unknown as React.MouseEvent<HTMLImageElement>);
  };

  const handleError = (event: React.SyntheticEvent<HTMLImageElement>) => {
    setStatus({ error: true, loading: false });
    onError?.(event as unknown as React.MouseEvent<HTMLImageElement>);
  };

  const renderLoadingIcon = () => {
    if (loadingIcon == null) {
      return null;
    }
    return <span className={clsx(bem('loading-icon'))}>{loadingIcon}</span>;
  };

  const renderErrorIcon = () => {
    if (errorIcon == null) {
      return null;
    }
    return <span className={clsx(bem('error-icon'))}>{errorIcon}</span>;
  };

  const renderPlaceholder = () => {
    if (status.loading && showLoading) {
      return <div className={clsx(bem('loading'))}>{renderLoadingIcon()}</div>;
    }
    if (status.error && showError) {
      return <div className={clsx(bem('error'))}>{renderErrorIcon()}</div>;
    }
    return null;
  };

  const renderImage = () => {
    if (status.error || !src) {
      return null;
    }
    const attrs = {
      className: clsx(bem('img')),
      style: {
        objectFit: fit,
      },
    };
    return (
      <img
        ref={imgRef}
        alt={alt}
        src={src}
        onLoad={handleLoad}
        onError={handleError}
        {...attrs}
        {...rest}
      />
    );
  };

  return (
    <div
      className={clsx(
        className,
        bem({
          block,
          round,
        }),
      )}
      style={computedStyle}
      onClick={onClick as React.MouseEventHandler<HTMLDivElement>}
    >
      {renderImage()}
      {renderPlaceholder()}
      {children}
    </div>
  );
};

export default Image;
